<template>
  <div>
    <el-dialog
      title="选择考试"
      ref="proctDialog"
      :visible.sync="proctVisible"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      width="650px"
      top="200px"
    >
      <el-row>
        <el-col>
          <span style="display: block; margin: 0px 0 0px 0">请选择监考的考试：</span
          ><br />
          <el-select
            v-model="choseExam"
            filterable
            placeholder="请选择"
            style="width: 600px"
          >
            <el-option
              v-for="item in exams"
              :key="item.examUuid"
              :label="item.examName"
              :value="item.examUuid"
            >
              <span style="margin-right: 18px; display: inline-block; width: 270px">{{
                item.examName
              }}</span>
              <span style="margin-right: 30px">{{
                "开考时间：" + formateDate(item.beginTime)
              }}</span>
              <span style="float: right">{{
                item.status === 0 ? "未开始" : "已开考"
              }}</span>
            </el-option>
          </el-select>
        </el-col>
      </el-row>
      <el-row style="margin-top: 15px">
        <el-col
          ><el-button
            type="primary"
            :disabled="choseExam === '' || choseExam === null || choseExam === undefined"
            @click="openProcto"
            >进入监考</el-button
          ></el-col
        >
      </el-row>
    </el-dialog>

    <div ref="mainDiv">
      <el-card
        class="card"
        style="width: 384px"
        v-if="students === [] || students === null"
      >
        <div style="padding: 14px">
          <i class="el-icon-info" style="font-size: 30px"
            ><span
              style="
                font-size: 15px;
                height: 30px;
                line-height: 30px;
                vertical-align: middle;
              "
              >&nbsp;当前考试无学生进入！</span
            ></i
          >
        </div>
      </el-card>
    </div>
  </div>
</template>

<script>
import DateUtils from "../../utils/DateUtils.js";
var _this;
export default {
  data() {
    return {
      exams: [],
      choseExam: "",
      students: [],
      allstudents:[],
      toDelStudents: [],
      toAddStudents: [],
      proctVisible: true,
      isChose: false,
      query: {
        workType: 1,
        fkexamName: "",
      },
      promiseTimer: {},

      // 以下为websocet所需变量
      websocket: {}, // webscoket连接
      studentMap: new Map(), // 学生map key-> userId value -> Object (pc...)
      teacherId: sessionStorage.getItem("userId"),
      loginToken: sessionStorage.getItem("ClientToken"),
      websocketUrl: "ws://localhost:8989/wsserver/",
      isCaller: false,
      isWebscoket: false,
      iceServer: {
        iceServers: [
          {
            url: "xxxxxxxxxx",
          },
          {
            url: "xxxxxxxxxxx",
            username: "xxxxxxxxxx",
            credential: "xxxxxxxxxxx",
          },
        ],
      },
    };
  },
  methods: {
    getExams() {
      this.$post("/examwork/getexams", this.query).then((res) => {
        if (res.code === 0) {
          this.exams = res.data;
        } else {
          console.log(res.msg);
          this.$message.error(res.msg);
        }
      });
    },
    formateDate(date) {
      return DateUtils.utc2beijing(date);
    },
    // 进入考试按钮点击事件
    async openProcto() {
      _this.proctVisible = false;
      _this.isChose = true;
      _this.initWebsocket();
    },
    // 获取学生列表
    async getStudents() {
      await _this
        .$post("examwork/getstudents", { examUuid: _this.choseExam })
        .then((res) => {
          console.log(res);
          if (res.code === 0) {
            _this.toAddStudents = []
            _this.toDelStudents = []
            _this.allstudents = JSON.parse(JSON.stringify(res.data));
            let newIds = res.data.map(item=>{
              return item.id
            })
              newIds.forEach(item => {
                  if (_this.students.indexOf(item) === -1) {
                    _this.toAddStudents.push(item)
                  }
              })
              _this.students.forEach(item=>{
                if (newIds.indexOf(item) === -1) {
                  _this.toDelStudents.push(item)
                }
              })
            _this.students = JSON.parse(JSON.stringify(newIds))
          } else {
            _this.$message.error("获取考生列表失败！");
          }
        });
    },
    // 初始化 总 监考页面
    initMain() {
      if (_this.students === null) {
        return;
      }
      _this.toDelStudents.forEach(item=>{
        let dom = document.getElementById("stu-" + item);
        if (dom !== null && dom !== undefined) {
          dom.remove();
        }
      })
      _this.toAddStudents.forEach((item) => {
        let dom = document.getElementById("stu-" + item);
        if (dom === null || dom === undefined) {
          _this.initOne(item);
        }
      });
    },
    // 初始化 单 监考页面
    initOne(id) {
      let stus = _this.allstudents.filter(item => {
        return item.id === id
      })
      let stu = stus[0]
      let parent = _this.$refs.mainDiv;
      let divchild = document.createElement("div");
      divchild.className = "div-stu";
      divchild.id = "stu-" + stu.id;

      let video = document.createElement("video");
      video.id = "stuVideo-" + stu.id;
      // video.setAttribute('width', '66.7%')
      video.className = "video-stu";
      video.autoplay = true;
      video.height = 195;
      video.width = 260;

      let spanchild = document.createElement("span");
      spanchild.className = "span-stu";
      spanchild.innerHTML = stu.userAccount + "-" + stu.userName;

      divchild.appendChild(video);
      divchild.appendChild(spanchild);
      parent.appendChild(divchild);
    },

    /**
     * 以下为websocket 连接所需
     */
    initWebsocket() {
      if ("WebSocket" in window) {
        _this.websocket = new WebSocket(
          _this.websocketUrl + _this.loginToken + "/" + _this.choseExam
        );
        console.log("链接已建立");
        _this.websocket.addEventListener("open", function () {
          _this.isWebscoket = true;
        });
        // 接收服务器数据
        _this.websocket.onmessage = (evt) => {
          const receivedMsg = evt.data;
          const jsonMsg = JSON.parse(receivedMsg);
          if (jsonMsg !== null && jsonMsg !== "") {
            var head = jsonMsg.head;
            var data = jsonMsg.data;
            // 处理信息
            switch (head) {
              case "sendTo":
                _this.sendTo(data);
                break;
              case "videoCall":
                _this.videocall(jsonMsg, data.fromUser);
                break;
            }
          }
        };
      } else {
        _this.$message.error("与服务器通讯连接建立失败！");
        _this.isWebscoket = false;
      }
    },
    async beginSend() {
      await _this.getStudents();
      _this.initMain();
      _this.sendAllRequest();
    },
    // 向学生列表发送请求
    sendAllRequest() {
      if (_this.toAddStudents === null || _this.toAddStudents === undefined) {
        return;
      }
      _this.toAddStudents.forEach((element) => {
        _this.sendRequestCall(element);
      });
    },
    // 发送视频请求
    sendRequestCall(stu) {
      const requestCall = {
        head: "sendTo",
        data: {
          fromUser: _this.teacherId,
          toUser: stu,
          title: "From_Teacher_Call",
        },
      };
      _this.sendMessage(JSON.stringify(requestCall));
    },
    // 发送消息 私发
    sendMessage(message) {
      this.websocket.send(message);
    },
    // 接收私发消息
    sendTo(data) {
      var jsonData = JSON.parse(data);
      let pc;
      if (
        _this.studentMap.get(jsonData.fromUser) === null ||
        _this.studentMap.get(jsonData.fromUser) === undefined
      ) {
        pc = new RTCPeerConnection(_this.iceServer);
        _this.studentMap.set(jsonData.fromUser, pc);
      }
      // 判断消息是否为视频通话请求
      if (jsonData.title === "Request_Call") {
        // 接收视频通话
        _this.isCaller = false
        _this.receiveCall(false, jsonData.fromUser, pc)
        const str = {
          head: 'sendTo',
          data: {
            fromUser: _this.teacherId,
            toUser: jsonData.fromUser,
            title: 'Receive_Call'
          }
        }
        this.sendMessage(JSON.stringify(str))
      } else if (jsonData.title === "Receive_Call") {
        // _this.isCaller = true;
        // _this.receiveCall(true, jsonData.fromUser, pc);
      } else {
        console.log(jsonData);
      }
    },
    // 接收视频通话 进行webrtc通信操作
    receiveCall(isCaller, user, pc) {
      // 发送ICE候选到其他客户端
      _this.studentMap.get(user).onicecandidate = (event) => {
        if (event.candidate !== null) {
          let str = JSON.stringify({
            head: "videoCall",
            data: {
              fromUser: _this.teacherId,
              toUser: user,
              event: "_ice_candidate",
              data: {
                candidate: event.candidate,
              },
            },
          });
          _this.sendMessage(str);
        }
      };

      // 如果检测到媒体流连接到本地，将其绑定到一个video标签上输出
      _this.studentMap.get(user).onaddstream = (event) => {
        console.log(event);
        document.getElementById("stuVideo-" + user).srcObject =
          event.stream
      };

      _this.studentMap.get(user).addStream(new MediaStream);
          // 如果是发起方则发送一个offer信令
          if (isCaller) {
            _this.studentMap.get(user).createOffer(
              (desc) => {
                _this.studentMap.get(user).setLocalDescription(desc);
                const str = JSON.stringify({
                  head: "videoCall",
                  data: {
                    fromUser: _this.teacherId,
                    toUser: user,
                    event: "_offer",
                    data: {
                      sdp: desc,
                    },
                  },
                });
                _this.sendMessage(str);
              },
              function (error) {
                console.log("Failure callback: " + error);
              }
            );
          }
     
    },
    videocall(event, user) {
      let pc = _this.studentMap.get(user);
      var json = event.data;
      // 如果是一个ICE的候选，则将其加入到PeerConnection中，否则设定对方的session描述为传递过来的描述
      if (json.event === "_ice_candidate") {
        pc.addIceCandidate(new RTCIceCandidate(json.data.candidate));
      } else {
        pc.setRemoteDescription(new RTCSessionDescription(json.data.sdp));
        // 如果是一个offer，那么需要回复一个answer
        if (json.event === "_offer") {
          pc.createAnswer(
            (desc) => {
              _this.studentMap.get(user).setLocalDescription(desc);
              const str = JSON.stringify({
                head: "videoCall",
                data: {
                  fromUser: _this.teacherId,
                  toUser: user,
                  event: "_answer",
                  data: {
                    sdp: desc,
                  },
                },
              });
              _this.sendMessage(str);
            },
            function (error) {
              console.log("Failure callback: " + error);
            }
          );
        }
      }
    },
  },
  created() {
    _this = this;
    this.getExams();
  },
  computed: {},
  watch: {
    isWebscoket(val, oldVal) {
      //普通的watch监听
      if (_this.isWebscoket === true) {
        _this.beginSend();
        _this.promiseTimer = setInterval(function () {
        _this.beginSend();
      }, 60 * 1000);
      }
    },
  },
  mounted() {},
};
</script>
<style>
.card {
  margin: 0 5px 15px 5px;
  width: 24%;
  border-radius: 15px;
  display: inline-block;
  background-color: #f5f5f5;
  /* background-image: linear-gradient(141deg, #a7cffcec 0%, #a7cffcec 51%, #a7cffcec 75%); */
}
.div-stu {
  float: left;
  width: 260px;
  height: 220px;
  padding: 3px;
  background-color: #bebebed8;
  margin: 5px;
}
.video-stu {
  /* background-color: red; */
  border-style: solid;
  border-width: 1px;
}
.span-stu {
  display: block;
  margin-left: 5px;
  /* background-color: blue; */
}
</style>
